#include <iostream>
#include <vector>
#include "mutex.hpp"
#include "sem.hpp"

using namespace MyMutex;
using namespace MySem;

const int defaultCap = 5;

template <typename T>
class RingQueue
{
public:
    RingQueue(const int cap = defaultCap)
        : _Ringq(cap), _capacity(cap)
        , _consumer_sem(0), _producer_sem(cap)
        , _consumer_step(0), _producer_step(0)
    {}

    ~RingQueue() {}

    void emplace(const T& data)
    {
        // 多生产，多消费
        // 需要维护生产者之间的互斥，以及消费者之间的互斥 --- 加锁

        _producer_sem.P();
        // 加锁
        _producer_mutex.lock();

        _Ringq[_producer_step++] = data;
        _producer_step %= _capacity;

        // 解锁
        _producer_mutex.unlock();
        _consumer_sem.V();

        //// 生产者插入数据
        //// 单生产
        //// 1.申请信号量
        //_producer_sem.P();

        //// 2.生产
        //_Ringq[_producer_step++] = data;

        //// 3.维护环形特性，避免越界
        //_producer_step %= _capacity;

        //// 4.生产一个，消费者就可以消费了，增加数据信号量
        //_consumer_sem.V();
    }

    void pop(T* out)
    {
        // 消费者获取数据
        // 单消费
        // 1.申请信号量
        _consumer_sem.P();

        // 加锁
        _consumer_mutex.lock();

        // 2.消费
        *out = _Ringq[_consumer_step++];

        // 3.维护环形特性，避免下标越界
        _consumer_step %= _capacity;

        // 解锁
        _consumer_mutex.unlock();

        // 4.消费一个，就有了空盘子，增加空位置信号量
        _producer_sem.V();
    }
private:
    std::vector<T> _Ringq; // 数组模拟环形队列
    int _capacity;         // 环形队列容量上限

    // 生产者消费者信号量---空信号量，有数据信号量
    sem _consumer_sem;
    sem _producer_sem;

    // 消费者生产者下标
    int _consumer_step;
    int _producer_step;

    // 锁---用来维护生产者之间，消费者之间的互斥关系
    mutex _consumer_mutex;
    mutex _producer_mutex;
};